package cn.icanci.ladybird.service.util.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.icanci.ladybird.common.result.JsonData;
import cn.icanci.ladybird.common.util.file.MatrixToImageWriterUtils;
import cn.icanci.ladybird.common.util.cache.RedisUtils;
import cn.icanci.ladybird.config.AlipayConfig;
import cn.icanci.ladybird.pojo.entity.BuyerTicket;
import cn.icanci.ladybird.pojo.entity.OrderInfo;
import cn.icanci.ladybird.pojo.entity.OrderInfoTicketInfoMiddle;
import cn.icanci.ladybird.pojo.entity.TicketSeat;
import cn.icanci.ladybird.service.BuyerTicketService;
import cn.icanci.ladybird.service.OrderInfoService;
import cn.icanci.ladybird.service.OrderInfoTicketInfoMiddleService;
import cn.icanci.ladybird.service.TicketSeatService;
import cn.icanci.ladybird.service.util.AlipayService;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author: icanci
 * @date: Created in 2020/10/13 13:43
 * @classAction: 支付宝支付实现类
 */
@SuppressWarnings("all")
@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {
    @Autowired
    private OrderInfoService orderInfoService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private TicketSeatService serviceSeatService;
    @Autowired
    private OrderInfoTicketInfoMiddleService orderInfoTicketInfoMiddleService;
    @Autowired
    private BuyerTicketService buyerTicketService;
    @Autowired
    private AlipayConfig alipayConfig;

    /**
     * 支付宝支付调用
     *
     * @param httpResponse 响应
     * @param totalAmount  总价格
     * @param subject      订单名称
     * @param body         商品描述
     * @param orderInfoId  订单id
     * @throws IOException IO异常
     */
    @Override
    public void alipay(HttpServletResponse httpResponse, HttpServletRequest request, Long orderInfoId) throws IOException {
        //实例化客户端,填入所需参数
        AlipayClient alipayClient = new DefaultAlipayClient(
                alipayConfig.getGatewayUrl(),
                alipayConfig.getApp_id(),
                alipayConfig.merchant_private_key,
                alipayConfig.getFormat(),
                alipayConfig.getCharset(),
                alipayConfig.getAlipay_public_key(),
                alipayConfig.getSign_type()
        );
        AlipayTradePagePayRequest req = new AlipayTradePagePayRequest();
        //在公共参数中设置回跳和通知地址
        req.setNotifyUrl(alipayConfig.getNotify_url());
        req.setReturnUrl(alipayConfig.getReturn_url());
        //商户订单号，商户网站订单系统中唯一订单号，必填

        String outTradeNo = UUID.randomUUID().toString();
        // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。
        // m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
        // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。

        // 根据 orderInfoId 获取订单信息
        if (null != orderInfoId) {
            OrderInfo orderInfo = orderInfoService.queryById(orderInfoId);
            // 使用用户id和订单id拼接key
            Long userId = Long.valueOf(request.getAttribute("user_id").toString());
            String key = userId + "-oid";
            redisUtils.set(key, orderInfoId, 15, TimeUnit.MINUTES);
            String totalAmount = orderInfo.getOrderInfoTotalPrice().toString();
            String subject = orderInfo.getTicketDetailsInfo();
            String body = "欢迎购买 " + subject + " ，演出场馆在" + orderInfo.getTicketAddressVenue();
            // 获取订单生成的时间
            // 获取订单剩余的时间取出
            String timeoutExpress = 15 + "m";

            req.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
                    + "\"total_amount\":\"" + totalAmount + "\","
                    + "\"subject\":\"" + subject + "\","
                    + "\"body\":\"" + body + "\","
                    + "\"timeout_express\":\"" + timeoutExpress + "\","
                    + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
            String form = "";
            try {
                // 调用SDK生成表单
                form = alipayClient.pageExecute(req).getBody();
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
            httpResponse.setContentType("text/html;charset=" + alipayConfig.getCharset());
            // 直接将完整的表单html输出到页面
            httpResponse.getWriter().write(form);
            httpResponse.getWriter().flush();
            httpResponse.getWriter().close();
        }
    }

    @Override
    public void toAlipay(HttpServletResponse httpResponse, HttpServletRequest request, Long orderInfoId) throws Exception {
        //实例化客户端,填入所需参数
        AlipayClient alipayClient = new DefaultAlipayClient(
                alipayConfig.getGatewayUrl(),
                alipayConfig.getApp_id(),
                alipayConfig.merchant_private_key,
                alipayConfig.getFormat(),
                alipayConfig.getCharset(),
                alipayConfig.getAlipay_public_key(),
                alipayConfig.getSign_type()
        );
        AlipayTradePagePayRequest req = new AlipayTradePagePayRequest();
        //在公共参数中设置回跳和通知地址
        req.setNotifyUrl(alipayConfig.getNotify_url());
        req.setReturnUrl(alipayConfig.getReturn_url());
        //商户订单号，商户网站订单系统中唯一订单号，必填

        String outTradeNo = UUID.randomUUID().toString();
        // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。
        // m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。
        // 该参数数值不接受小数点， 如 1.5h，可转换为 90m。

        // 根据 orderInfoId 获取订单信息
        if (null != orderInfoId) {
            OrderInfo orderInfo = orderInfoService.queryById(orderInfoId);
            // 使用用户id和订单id拼接key
            String totalAmount = orderInfo.getOrderInfoTotalPrice().toString();
            String subject = orderInfo.getTicketDetailsInfo();
            String body = "欢迎购买 " + subject + " ，演出场馆在" + orderInfo.getTicketAddressVenue();
            // 获取订单生成的时间
            Date createTime = orderInfo.getCreateTime();
            Date nowDatae = new Date();
            long between = DateUtil.between(createTime, nowDatae, DateUnit.MINUTE);
            log.info("AlipayServiceImpl.toAlipay - " + between);
            // 获取订单剩余的时间取出
            // 10 - 1
            // 10 - 5
            // 15 - 4
            long remain = 15 - between;
            if (remain <= 0) {
                throw new Exception("订单超时-----");
            }
            String timeoutExpress = remain + "m";
            req.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
                    + "\"total_amount\":\"" + totalAmount + "\","
                    + "\"subject\":\"" + subject + "\","
                    + "\"body\":\"" + body + "\","
                    + "\"timeout_express\":\"" + timeoutExpress + "\","
                    + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
            String form = "";
            try {
                // 调用SDK生成表单
                form = alipayClient.pageExecute(req).getBody();
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
            httpResponse.setContentType("text/html;charset=" + alipayConfig.getCharset());
            // 直接将完整的表单html输出到页面
            httpResponse.getWriter().write(form);
            httpResponse.getWriter().flush();
            httpResponse.getWriter().close();
        }
    }

    /**
     * 返回处理结果
     *
     * @param request  请求
     * @param response 响应对象
     * @return 返回JsonData对象
     * @throws IOException        IO异常
     * @throws AlipayApiException alipay 异常
     */
    @Override
    public JsonData returnUrl(HttpServletRequest request, HttpServletResponse response) throws Exception {
        log.info("=================================同步回调=====================================");
        // 获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("utf-8"), "utf-8");
            params.put(name, valueStr);
        }

        //查看参数都有哪些
        System.out.println(params);
        boolean signVerified = AlipaySignature.rsaCheckV1(params,
                alipayConfig.getAlipay_public_key(),
                alipayConfig.getCharset(),
                alipayConfig.getSign_type());
        // 调用SDK验证签名
        //验证签名通过
        if (signVerified) {
            // 商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
            // 支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
            // 付款金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

            // 打印数据
            log.info("商户订单号=" + out_trade_no);
            log.info("支付宝交易号=" + trade_no);
            log.info("付款金额=" + total_amount);

            // 支付成功，修复支付状态 和座位的状态 还有电子票
            // 从Redis得到订单id 根据订单id修改状态
            Long userId = Long.valueOf(request.getAttribute("user_id").toString());
            String key = userId + "-oid";
            Long orderInfoId = Long.valueOf(redisUtils.get(key).toString());
            if (null != orderInfoId) {
                OrderInfo orderInfo = orderInfoService.queryById(orderInfoId);
                // 设置订单的状态
                orderInfo.setOrderInfoStatus(1);
                // 根据订单id获取座位的集合，设置状态已经被选走
                List<Long> seats = (List<Long>) redisUtils.get(String.valueOf(orderInfoId));
                if (null != seats) {
                    for (Long seat : seats) {
                        TicketSeat ticketSeat = serviceSeatService.queryById(seat);
                        ticketSeat.setTicketState(0);
                        serviceSeatService.update(ticketSeat);
                    }
                    // 设置电子票信息
                    StringBuilder text = new StringBuilder();
                    text.append("感谢您使用票虫网购票，请保管好您的电子票，请勿给他人查看！\n\n");
                    text.append("商品名字：").append(orderInfo.getTicketDetailsInfo()).append("\n")
                            .append("订单编号：").append(orderInfo.getOrderNumber()).append("\n")
                            .append("票品时间：").append(DateUtil.format(orderInfo.getTicketTime(), "yyyy-MM-dd HH:mm:ss")).append("\n")
                            .append("下单时间：").append(DateUtil.format(orderInfo.getOrderInfoTime(), "yyyy-MM-dd HH:mm:ss")).append("\n")
                            .append("座位：").append(orderInfo.getSeats()).append("\n")
                            .append("总价：").append(orderInfo.getOrderInfoTotalPrice()).append("\n")
                            .append("购票人：").append("\n");
                    // 根据订单id查询购票人的信息
                    OrderInfoTicketInfoMiddle infoMiddle = orderInfoTicketInfoMiddleService.queryByOrderInfoIdAndTicketId(orderInfoId, orderInfo.getOrderInfoTicketDetailsId());
                    String[] buyers = infoMiddle.getBuyers().split(",");
                    ArrayList<BuyerTicket> buyerTickets = new ArrayList<>();
                    for (String buyer : buyers) {
                        BuyerTicket buyerTicket = buyerTicketService.queryById(Long.valueOf(buyer));
                        Integer documentType = buyerTicket.getBuyerTicketDocumentType();
                        String type = null;
                        switch (documentType) {
                            case 1:
                                type = "身份证";
                                break;
                            case 2:
                                type = "护照";
                                break;
                            default:
                                break;
                        }
                        text.append("姓名：").append(buyerTicket.getBuyerTicketUsername()).append("\n")
                                .append("证件类型：").append(type).append("\n")
                                .append("证件号：").append(buyerTicket.getBuyerTicketIdCardNumber()).append("\n");
                    }
                    // 上传数据到服务器 生成订单的二维码
                    String orderInfoImg = MatrixToImageWriterUtils.createOrderInfoImg(text.toString(), orderInfo.getTicketDetailsInfo(), orderInfo.getOrderInfoId());
                    // 设置二维码
                    orderInfo.setOrderInfoTicketEleImgUrl(orderInfoImg);
                    orderInfoService.update(orderInfo);
                    alipayConfig.logResult("支付成功，订单编号：" + orderInfo.getOrderInfoId());
                    // 跳转付款成功页面
                    return JsonData.builderSuccess("支付成功");
                }
            }
            // 跳转付款失败页面
            alipayConfig.logResult("支付失败");
            return JsonData.builderError("支付失败");
        } else {
            // 跳转付款失败页面
            alipayConfig.logResult("支付失败");
            return JsonData.builderError("支付失败");
        }
    }
}
